﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Collections;
using System.Windows.Forms;
using System.Diagnostics;
using System.ComponentModel;
using VNPT.Data;

namespace VNPT.DoiSoat
{
    public static class Dbf
    {
        public static string FileName = String.Empty; // name of file
        public static string TableName = String.Empty; // table name to create
        public static string DbfFile = String.Empty; // path + filename to the dbf file

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct DBFHeader
        {
            public byte version;
            public byte updateYear;
            public byte updateMonth;
            public byte updateDay;
            public Int32 numRecords;
            public Int16 headerLen;
            public Int16 recordLen;
            public Int16 reserved1;
            public byte incompleteTrans;
            public byte encryptionFlag;
            public Int32 reserved2;
            public Int64 reserved3;
            public byte MDX;
            public byte language;
            public Int16 reserved4;
        }

        // This is the field descriptor structure. There will be one of these for each column in the table.
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct FieldDescriptor
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
            public string FieldName;
            public char FieldType;
            public Int32 Address;
            public byte FieldLen;
            public byte Count;
            public Int16 reserved1;
            public byte workArea;
            public Int16 reserved2;
            public byte flag;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
            public byte[] reserved3;
            public byte indexFlag;
        }

        //public static MyField[] arrField = null;

        internal static bool CreateControlFile(string Path_Dir, ArrayList SelectedFields, ArrayList OriginalFields)
        {
            FileInfo inf = new FileInfo(Path_Dir);

            if (File.Exists(Path_Dir + Dbf.FileName + ".ctl"))
            {
                File.Delete(Path_Dir + Dbf.FileName + ".ctl");
            }

            int fieldIndex = 0;
            int pos = 0;
            string number;
            string strType = String.Empty;

            StringBuilder strWrite = new StringBuilder();
            StreamWriter hCtrlFile = new StreamWriter(Path_Dir + Dbf.FileName + ".ctl");

            try
            {
                int len = 1;
                foreach (FieldDescriptor field in OriginalFields)
                {
                    len += field.FieldLen;
                }

                hCtrlFile.WriteLine("LOAD DATA");
                hCtrlFile.WriteLine("INFILE '" + Path_Dir + Dbf.FileName + ".DAT' " + "\"FIX " + len.ToString() + "\"");
                hCtrlFile.WriteLine("APPEND INTO TABLE " + Dbf.TableName);
                hCtrlFile.WriteLine("(");

                pos = 0;
                len = 0;
                fieldIndex = 0;

                // Loop through each field in a record
                foreach (FieldDescriptor field in SelectedFields)
                {
                    switch (field.FieldType)
                    {
                        case 'C':
                            strType = "CHAR(" + field.FieldLen.ToString() + ") \"TRIM(:" + field.FieldName + ")\"";
                            break;
                        case 'N':
                            if (field.Count > 0)
                            {
                                strType = "DECIMAL EXTERNAL";
                            }
                            else
                            {
                                strType = "INTEGER EXTERNAL";
                            }
                            break;
                        case 'D':
                            strType = "DATE \"YYYYMMDD\" NULLIF " + field.FieldName + "=BLANKS";
                            break;
                    }

                    strWrite = new StringBuilder("\t \"" + field.FieldName + "\" \t"
                        + "POSITION(" + (field.Address + 1).ToString() + ":"
                        + ("\"" + field.Address + "\"" + field.FieldLen).ToString() + ") " + strType);

                    if (fieldIndex < SelectedFields.Count - 1)
                    {
                        strWrite.Append(",");
                    }
                    fieldIndex++;
                    hCtrlFile.WriteLine(strWrite.ToString());
                }
                hCtrlFile.WriteLine(")");
                hCtrlFile.Close();
                return true;
            }
            catch (System.Exception ex)
            {
                hCtrlFile.Close();
                DevExpress.XtraEditors.XtraMessageBox.Show("Error: " + ex.Message);
                return false;
            }
        }
        public static bool CreateDataFile(string DbfFile)
        {
            string FilePath = Path.GetDirectoryName(Application.ExecutablePath) + "\\";

            if (File.Exists(FilePath + Dbf.FileName + ".dat"))
            {
                File.Delete(FilePath + Dbf.FileName + ".dat");
            }

            BinaryReader br = null;
            try
            {
                // Read the header into a buffer
                br = new BinaryReader(File.OpenRead(DbfFile));
                byte[] buffer = br.ReadBytes(Marshal.SizeOf(typeof(DBFHeader)));

                // Marshall the header into a DBFHeader structure
                GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                DBFHeader header = (DBFHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(DBFHeader));
                handle.Free();

                ((FileStream)br.BaseStream).Seek(header.headerLen, SeekOrigin.Begin);

                FileStream hDataFile = new FileStream(FilePath + Dbf.FileName + ".dat", FileMode.Create);

                for (int counter = 0; counter <= header.numRecords; counter++)
                {
                    buffer = br.ReadBytes(header.recordLen);
                    Console.WriteLine(">> CL File: {0} -- {1}", counter, header.numRecords);
                    //Console.WriteLine(hDataFile.Length);
                    hDataFile.Write(buffer, 0, buffer.Length);
                }
                hDataFile.Close();
                br.Close();
                return true;
            }
            catch
            {
                br.Close();
                return false;
            }
        }

        internal static void BulkInsertWithSqlLoader(string s, BackgroundWorker bg, int AllRows)
        {
            try
            {
                ProcessStartInfo si = new ProcessStartInfo();
                si.FileName = "sqlldr.exe";
                si.Arguments = s;
                si.RedirectStandardOutput = true;
                si.RedirectStandardError = true;
                si.UseShellExecute = false;
                si.CreateNoWindow = true;

                DevExpress.XtraEditors.XtraMessageBox.Show(si.Arguments);
                using (Process p = Process.Start(si))
                {

                    StreamReader streamOutput = p.StandardOutput;
                    //Console.WriteLine(streamOutput.ReadToEnd());
                    while (!p.StandardOutput.EndOfStream)
                    {
                        var _out = p.StandardOutput.ReadLine();
                        var _tem = _out.Replace("Commit point reached - logical record count", "");
                        int so = 0;
                        int.TryParse(_tem.Trim(), out so);
                        bg.ReportProgress(so * 100 / AllRows);
                        // Console.WriteLine(_out);
                        //Application.DoEvents();
                    }
                    p.WaitForExit();
                    if (p.ExitCode == 0)
                    {
                        string stdOutput = p.StandardOutput.ReadToEnd();
                    }
                    else
                    {
                        string stdOutput = p.StandardError.ReadToEnd();
                    }


                    p.Dispose();
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        internal static string UploadWithSqlLoader(string s)
        {
            try
            {
                ProcessStartInfo si = new ProcessStartInfo();
                si.FileName = "sqlldr.exe";
                si.Arguments = s;
                si.RedirectStandardOutput = true;
                si.RedirectStandardError = true;
                si.UseShellExecute = false;
                si.CreateNoWindow = true;
                string stdOutput;

                using (Process p = Process.Start(si))
                {
                    //Application.DoEvents();
                    StreamReader streamOutput = p.StandardOutput;
                    Console.WriteLine(streamOutput.ReadToEnd());
                    p.WaitForExit();
                    if (p.ExitCode == 0)
                    {
                        stdOutput = p.StandardOutput.ReadToEnd();
                    }
                    else
                    {
                        stdOutput = p.StandardError.ReadToEnd();
                    }
                    p.Dispose();
                }

                return stdOutput;
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        internal static string CreateTableFromDbf(string TableName, ArrayList Fields, DbNetData db)
        {
            string result = String.Empty;
            int i = 0;
            StringBuilder strWrite = new StringBuilder();
            StringBuilder strType = new StringBuilder();
            StringBuilder Query = new StringBuilder();
            try
            {
                Query = new StringBuilder("CREATE TABLE " + TableName + "(");

                foreach (FieldDescriptor field in Fields)
                {
                    switch (field.FieldType)
                    {
                        //case 'C':
                        case 'C':
                            strType = new StringBuilder("VARCHAR2(" + field.FieldLen.ToString() + ")");
                            break;
                        case 'N':
                            strType = new StringBuilder("NUMBER(" + field.FieldLen.ToString());
                            if (field.Count > 0)
                            {
                                strType.Append(", " + field.Count.ToString() + ")");
                            }
                            else
                            {
                                strType.Append(")");
                            }
                            break;
                        case 'D':
                            strType = new StringBuilder("DATE");
                            break;
                    }
                    strWrite = new StringBuilder("\"" + field.FieldName + "\" " + "\t" + strType.ToString());
                    if (i < Fields.Count - 1)
                    {
                        strWrite.Append(",");
                    }
                    Query.Append(strWrite.ToString());
                    i++;
                }

                Query.Append(")");
                // Connection conn = new Connection();
                //  conn.ExecuteNonQuery(Query.ToString());
                db.ExecuteNonQuery(new CommandConfig(Query.ToString()));
                return result;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        internal static string CreateTable(string TableName, DevExpress.XtraGrid.Views.Grid.GridView view, DbNetData Db)
        {
            string result = String.Empty;
            int i = 0, n = 0;
            StringBuilder strField = new StringBuilder();
            StringBuilder Query = new StringBuilder();
            try
            {
                result = "";
                n = view.RowCount;
                Query = new StringBuilder("CREATE TABLE " + TableName + "(");
                for (i = 0; i < n; i++)
                {
                    if (view.GetRowCellDisplayText(i, "Field").ToString() == "" || view.GetRowCellDisplayText(i, "Type").ToString() == "")
                        break;

                    strField = new StringBuilder(view.GetRowCellDisplayText(i, "Field").ToString() + "\t" + view.GetRowCellDisplayText(i, "Type").ToString());
                    Query.Append(strField.ToString() + ",");
                }
                Query = Query.Remove(Query.Length - 1, 1);
                Query.Append(")");
                //Connection conn = new Connection();
                //conn.ExecuteNonQuery(Query.ToString());
                Db.ExecuteNonQuery(new CommandConfig(Query.ToString()));

                return result;
            }
            catch (System.Exception ex)
            {
                return ex.Message;
            }
        }

        internal static string GetFileName(string strPath)
        {
            if (strPath == "")
                return string.Empty;

            int i = (strPath.Trim() == "" && "\\" == "") ? 0 : (strPath.Trim().LastIndexOf("\\") + 1);
            i = (i <= 0) ? 0 : i;
            string FileName = strPath.Substring(i);
            FileName = FileName.Substring(0, ((FileName == "" && "." == "") ? 0 : (FileName.LastIndexOf("."))));
            return FileName;
        }
    }
}
